#include <SDL/SDL.h>
#include <SDL/SDL_opengl.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>

#include "puzzle.h"
#include "renderer.h"

//GLUI
#include "GLMessageBox.h"
#include "GLButton.h"
#include "texture.h"
#include "TTFFont.h"
#include "TextObject.h"

#define INTERVAL 30
Renderer *r = NULL; 
Puzzle *p = NULL;//(5);
float angles[2];
int start[2] = {0, 0};
float wrldDims[3];

Texture *g_CubeTex = NULL;
GLButton *resetButton = NULL;
GLButton *helpButton = NULL;
TextObject *timerText = NULL;
Uint32 timeCounter = 0;

void display()
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    r->set3DProjection();
    glPushMatrix();
    glTranslatef(wrldDims[0]/2.0f, wrldDims[1]/2.0f, wrldDims[2]/2.0f);
    glRotatef(angles[0], 0, 1, 0);
    glRotatef(angles[1], cos(angles[0] * 3.14/180), 0, sin(angles[0] * 3.14/180));
    glTranslatef(-wrldDims[0]/2.0f, -wrldDims[1]/2.0f, -wrldDims[2]/2.0f);
    glBindTexture(GL_TEXTURE_2D, g_CubeTex->GetTexID());
    r->renderScene();
    glPopMatrix();     
    r->set2DProjection();    
    int x, y;
    SDL_GetMouseState(&x, &y);  
    resetButton->show();
    helpButton->show();
    timerText->drawText(0, HEIGHT);
    GLui::drawCursor(x, HEIGHT-y, g_GLuiCursorTex->GetTexID());
    SDL_GL_SwapBuffers();
}

void motion(int x, int y)
{
    if(start[0] > 0 && start[1] > 0)
    {
        angles[0] += (x - start[0])/5.0;
        angles[1] += (y - start[1])/5.0;
        start[0] = x;
        start[1] = y;
    }
}

void Quit(int val)
{
    SDL_SetTimer(INTERVAL, NULL);
    delete r;
    delete timerText;
    delete g_GLuiFont;
    delete g_GLuiCursorTex;
    delete resetButton;
    delete helpButton;
    //quit sdl
    SDL_Quit();
    exit(val);
}

void keyboard(SDLKey key)
{
    switch(key)
    {
        case SDLK_RIGHT:
            printf("right\n");
            p->rotXY();
            break;
        case SDLK_LEFT:
            printf("left\n");
            p->rotXY(true);
            break; 
        case SDLK_UP:
            printf("up\n");
            p->rotZY(true);
            break;
        case SDLK_DOWN:
            printf("down\n");
            p->rotZY();
            break;
        case SDLK_ESCAPE:
            Quit(0);
    }
}

void UIinputHandler(int &x, int &y, bool &clicked)
{
    SDL_PumpEvents();
    Uint8 *keystate = SDL_GetKeyState(NULL);
    if(keystate[SDLK_ESCAPE])
    {
        return;
        //Quit(0);
    }
    if(SDL_GetMouseState(&x, &y)&SDL_BUTTON(1))
    {
        clicked = true;
    }
    else
        clicked = false;
    y = HEIGHT - y;
}

void InputHandler(SDL_Event &evnt)
{
    switch(evnt.type)
    {
        case SDL_MOUSEBUTTONDOWN:
            start[0] = evnt.button.x;
            start[1] = evnt.button.y;
            break;
    
        case SDL_MOUSEBUTTONUP:
            start[0] = -1;
            start[1] = -1;
            break;
        case SDL_MOUSEMOTION:            
            motion(evnt.button.x, evnt.button.y);
            break;
        case SDL_KEYUP:
            keyboard(evnt.key.keysym.sym);
            break;
        case SDL_QUIT:        
            Quit(0);
    }
}
int size = 6;
void ResetClicked()
{
    delete r;
    delete p;    
    p = new Puzzle(size);
    r = new Renderer(p);
    r->getWorldDims(wrldDims);
    timeCounter = 0;
}

void HelpClicked()
{
    r->set2DProjection();
    int ret = GLMessageBox::information("Slide Puzzle", "Move the RED block to GREEN block using arrow keys to rotate the world."
        "The RED block always falls DOWN.", "Resume", "Quit");
    if(ret)//"Quit" clicked
        Quit(0);
}

Uint32 timer(Uint32 val)
{
    p->update();
    return INTERVAL;
}

int main(int argc, char **argv)
{
    int VideoFlags = 0;
    SDL_Surface *MainWindow;

    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)  // try to initialize SDL video module
    {
        printf("SDL ERROR:%s\n", SDL_GetError());   // report error if it fails
        Quit(0);
    }
    const SDL_VideoInfo *VideoInfo = SDL_GetVideoInfo();    // query SDL for information about our video hardware

    if (VideoInfo == NULL)  // if this query fails
    {
        printf("Failed getting Video Info : %s\n", SDL_GetError()); // report error
        Quit(0);
    }

    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);    // tell SDL that the GL drawing is going to be double buffered

    //VideoFlags = SDL_OPENGL;

    MainWindow = SDL_SetVideoMode(WIDTH, HEIGHT, 32, SDL_OPENGL | SDL_HWPALETTE );

    if (MainWindow == NULL) // if window creation failed
    {
        printf("Failed to Create Window : %s\n", SDL_GetError());   // report error
        Quit(0);
    }
    SDL_WM_SetCaption("Slide Puzzle", "Slide Puzzle");
    SDL_ShowCursor(false);

    GLMessageBox::setCallbacks(UIinputHandler, SDL_GL_SwapBuffers);

    //initialize the renderer .. the puzzle is already created global var
    p = new Puzzle(5);
    r = new Renderer(p); 
    r->getWorldDims(wrldDims);

    //initialize the GLui stuff
    g_GLuiFont = new TTFFont("fonts//larabieb.ttf", 20, 0);
    g_GLuiCursorTex = new Texture("images/green.tga");
    g_CubeTex = new Texture("images/cubetex.tga");
    g_GLuiCursorTex->Load();
    g_CubeTex->Load();
    timerText = new TextObject(g_GLuiFont);
    timerText->setColor(255, 255, 255);
    timerText->setText("Timer: 0 Secs");
    resetButton = new GLButton(WIDTH-110, HEIGHT-10, UIinputHandler, ResetClicked, "Reset");
    helpButton = new GLButton(WIDTH-110, HEIGHT-50, UIinputHandler, HelpClicked, "Help");
    r->set2DProjection();    
    int ret = GLMessageBox::information("Slide Puzzle", "Starting Puzzle Game", "Ok", "Cancel");
    if(ret == 1) //"Cancel" selected
    {
        Quit(0);
    }
    r->set3DProjection();
    
    
    SDL_SetTimer(INTERVAL, timer); 
    SDL_Event evnt;
    Uint32 prev_elapsed = SDL_GetTicks();
    while(1)
    {
        Uint32 elapsed_time = SDL_GetTicks();
        if(elapsed_time - prev_elapsed > 1000) //returns time in millisecs
        {
            timeCounter++;
            char buff[100];
            sprintf(buff, "Timer:%3d Secs", timeCounter);
            timerText->setText(buff);
            prev_elapsed = elapsed_time;
        }
        if(p->isSolved())
        {
            char buff[100];
            sprintf(buff, "Puzzle Solved in %d Secs", timeCounter);
            int ret = GLMessageBox::information("Slide Puzzle", buff, "New", "Quit");
            if(ret == 0) //"New" Selected
            {
                if(argc > 1)
                    size = atoi(argv[1]);
                ResetClicked();
            }
            else    //"Quit" Selected
                Quit(0);
        }
        display();
        while(SDL_PollEvent(&evnt))
        {           
            InputHandler(evnt);
        }
    }
}
